`include "mips.h"
   
module wb (I4, RDaddr, WBsel);

input	[31:0]	I4;	// Stage 5 instruction

output	[4:0]	RDaddr;		
reg     [4:0]	RDaddr;	// Destination register address
output	[2:0]	WBsel;	
reg     [2:0]	WBsel;	// Stage 5 result select

//---------------------------------------------------------------------
// Control logic for the WB stage
// WBsel selects whether the data to be written back should come from 
// the load unit (LMDR) should be the link PC from a jal or jalr instruction
// or should be the output of the ALU.
//---------------------------------------------------------------------

always @(I4) begin
   casex ({I4[`op], I4[`function]})

      // Write back load data from cache
      {`LW,	 `dc6	}: WBsel = `select_wb_load;
      {`LBU,	 `dc6	}: WBsel = `select_wb_load;
      {`LB,	 `dc6	}: WBsel = `select_wb_load;
      {`LHU,     `dc6   }: WBsel = `select_wb_load;
      {`LH,      `dc6   }: WBsel = `select_wb_load;

      // Write back PC link value
      {`JAL,	 `dc6	}: WBsel = `select_wb_link;
      {`SPECIAL, `JALR	}: WBsel = `select_wb_link;

      // Write back result from ALU
      default		 : WBsel = `select_wb_alu;	
   endcase
end

/*---------------------------------------------------------------------
Decode destination register number

The following logic examines a 32-bit instruction and decodes the 
appropriate fields in order to find a register file destination 
address for the result.  If the operation does not write to the 
register file, decode_rd returns a destination register of zero. 
---------------------------------------------------------------------*/

// Compute destination register number
always @(I4) begin
   casex ({I4[`op], I4[`function]})
      // Load result goes to `rt register
      {`LW,	 `dc6	}: RDaddr = I4[`rt];
      {`LBU,	 `dc6	}: RDaddr = I4[`rt];
      {`LB,	 `dc6	}: RDaddr = I4[`rt];
      {`LHU,     `dc6   }: RDaddr = I4[`rt];
      {`LH,      `dc6   }: RDaddr = I4[`rt];

      // Immediate operation results go to `rt
      {`ADDI,	 `dc6	}: RDaddr = I4[`rt];
      {`ADDIU,	 `dc6	}: RDaddr = I4[`rt];
      {`SLTI,	 `dc6	}: RDaddr = I4[`rt];
      {`SLTIU,	 `dc6	}: RDaddr = I4[`rt];
      {`ANDI,	 `dc6	}: RDaddr = I4[`rt];
      {`ORI,	 `dc6	}: RDaddr = I4[`rt];
      {`XORI,	 `dc6	}: RDaddr = I4[`rt];
      {`LUI,	 `dc6	}: RDaddr = I4[`rt];

      // ALU operation results go to `rd register
      {`SPECIAL, `ADD	}: RDaddr = I4[`rd];
      {`SPECIAL, `ADDU	}: RDaddr = I4[`rd];
      {`SPECIAL, `SUB	}: RDaddr = I4[`rd];
      {`SPECIAL, `SUBU	}: RDaddr = I4[`rd];
      {`SPECIAL, `SLT	}: RDaddr = I4[`rd];
      {`SPECIAL, `SLTU	}: RDaddr = I4[`rd];
      {`SPECIAL, `AND	}: RDaddr = I4[`rd];
      {`SPECIAL, `OR	}: RDaddr = I4[`rd];
      {`SPECIAL, `XOR	}: RDaddr = I4[`rd];
      {`SPECIAL, `NOR	}: RDaddr = I4[`rd];

      // Note, other shift decode to be added...
      // Shift operations go to `rd register
      {`SPECIAL, `SLL	}: RDaddr = I4[`rd];
      {`SPECIAL, `SRL	}: RDaddr = I4[`rd];
      {`SPECIAL, `SRA	}: RDaddr = I4[`rd];
      {`SPECIAL, `SLLV	}: RDaddr = I4[`rd];
      {`SPECIAL, `SRLV	}: RDaddr = I4[`rd];
      {`SPECIAL, `SRAV	}: RDaddr = I4[`rd];

      // Link register is R31
      {`JAL,	 `dc6	}: RDaddr = `r31;
      {`SPECIAL, `JALR	}: RDaddr = `r31;

      // All other instruction results go to `r0
      default		 : RDaddr = `r0;
   endcase
end

endmodule













